#ifndef _FolderTree_CPP
#define _FolderTree_CPP
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include <Windows.H>
#include <ShlObj.H>
#include <Stdio.H>
#include <ShlOBJ.H>
#include <Stdlib.H>

#include "../Resources/Resource.H"

#include "NSWFL.H"
#include "Package.H"
#include "Entry.H"
#include "FolderTree.H"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL FolderTree::DeleteAllItems(void)
{
	return TreeView_DeleteAllItems(lhTreeHandle);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL FolderTree::GetTreeItemText(HTREEITEM htItem, char *outText)
{
    TVITEMEX tvItemEx;
    tvItemEx.hItem          = htItem;
    tvItemEx.mask           = TVIF_TEXT;
    tvItemEx.pszText        = outText;
    tvItemEx.cchTextMax     = MAX_PATH;
    return TreeView_GetItem(lhTreeHandle, &tvItemEx);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::SelectPath(char *szPath)
{
    bool Found = false;

    char szPartBuff[MAX_PATH + 1];
    char szTreeBuff[MAX_PATH + 1];

    HTREEITEM htItem = NULL;
    HTREEITEM htRoot = NULL;

    int Length = strlen(szPath);
    int RPos = 0;
    int WPos = 0;

    htRoot = TreeView_GetRoot(lhTreeHandle);
    htRoot = TreeView_GetNextItem(lhTreeHandle, htRoot, TVGN_CHILD);

    htItem = htRoot;

	while(true)
    {
        if(szPath[RPos] == '\\' || szPath[RPos] == '//' || RPos == Length)
        {
            szPartBuff[WPos] = '\0';

            Found = false;

            htItem = TreeView_GetNextItem(lhTreeHandle, htItem, TVGN_CHILD);
            GetTreeItemText(htItem, szTreeBuff);
            if(strcmpi(szTreeBuff, szPartBuff) == 0)
            {
                TreeView_Expand(lhTreeHandle, htItem, TVE_EXPAND);
                TreeView_SelectItem(lhTreeHandle, htItem);
                Found = true;
            }
            else{
                while((htItem = TreeView_GetNextItem(lhTreeHandle, htItem, TVGN_NEXT)) != NULL)
                {
                    GetTreeItemText(htItem, szTreeBuff);
                    if(strcmpi(szTreeBuff, szPartBuff) == 0)
                    {
                        TreeView_Expand(lhTreeHandle, htItem, TVE_EXPAND);
                        TreeView_SelectItem(lhTreeHandle, htItem);
                        Found = true;
                        break;
                    }
                }
            }

            if(!Found)
                return false;

            if(RPos == Length)
                break;

            WPos = 0;
        }
        else {
            szPartBuff[WPos] = szPath[RPos];
            WPos++;
        }

        RPos++;
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

HTREEITEM FolderTree::AddTreeViewItem(HTREEITEM hParent, char *inText, int iImage, int iSelImage)
{
    TV_INSERTSTRUCT MyTVIS;
    MyTVIS.item.hItem          = hParent;
    MyTVIS.item.pszText        = inText;
    MyTVIS.item.iImage         = iImage;
    MyTVIS.item.iSelectedImage = iSelImage;
    MyTVIS.item.mask           = TVIF_TEXT|TVIF_SELECTEDIMAGE|TVIF_IMAGE;
    MyTVIS.hParent             = hParent;
    MyTVIS.item.cchTextMax     = strlen(inText);
    return TreeView_InsertItem(lhTreeHandle, &MyTVIS);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::GetDesktopFolderPath(char *Desktop)
{
    DWORD SizeOfBuffer = MAX_PATH;

    if(IsWinNT())
    {
        if(Get_StringRegistryValue(HKEY_CURRENT_USER, SHELLFOLDERS, "Desktop", Desktop, SizeOfBuffer))
        {
            return true;
        }
        else return false;
    }
    else{
        if(Get_StringRegistryValue(HKEY_LOCAL_MACHINE, SHELLFOLDERS, "Common Desktop", Desktop, SizeOfBuffer))
        {
            return true;
        }
        else return false;
    }

    return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::IsAlreadyLoaded(char *inFolder)
{
    int LocalLoop = 0;

    while(LocalLoop < LoadedItems)
    {
        if(strcmpi(inFolder, AlreadyLoaded[LocalLoop]) == 0)
        {
            return true;
        }
        LocalLoop++;
    }
    return false;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::InitFolderTree(HWND hTreeHandle, HWND hButtonHandle, HWND hEditBoxHandle)
{
    lhTreeHandle = hTreeHandle;
    lhButtonHandle = hButtonHandle;
    lhEditBoxHandle = hEditBoxHandle;

	DeleteAllItems();

    if(!CreateTreeImageList())
    {
        return false;
    }

    if(!InitAlreadyLoaded())
    {
        return false;
    }

    if(!PopBrowseTree())
    {
        return false;
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::UnInitFolderTree(void)
{
	DeleteAllItems();

	if(!FreeAlreadyLoaded())
    {
        return false;
    }

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::InitAlreadyLoaded(void)
{
    int LocalLoop = 0;

    if((AlreadyLoaded = (char **) calloc(sizeof(char *), LOAD_TREE_ITEMS_INCREMENT)) == NULL)
    {
        return false;
    }

    MaxLoadedItems = LOAD_TREE_ITEMS_INCREMENT;

    LoadedItems = 0;

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::FreeAlreadyLoaded(void)
{
    int LocalLoop = 0;

    while(LocalLoop < LoadedItems)
    {
        free(AlreadyLoaded[LocalLoop]);
        AlreadyLoaded[LocalLoop] = NULL;
        LocalLoop++;
    }

    LoadedItems = 0;
    MaxLoadedItems = 0;

    free(AlreadyLoaded);

    AlreadyLoaded = NULL;

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::IndexDirectoryForSubItem(HTREEITEM SubLeaf, char *inFolder, bool IndexTwoDeep)
{
    if(IsAlreadyLoaded(inFolder))
    {
        return true;
    }

    WIN32_FIND_DATA FindData;
    HANDLE FileHandle = NULL;

    char DirTemp[MAX_PATH + 1];

    if(inFolder[strlen(inFolder) - 1] != '\\')
        sprintf(DirTemp, "%s\\*.*", inFolder);
    else sprintf(DirTemp, "%s*.*", inFolder);

    if((FileHandle = FindFirstFile(DirTemp, &FindData)) == INVALID_HANDLE_VALUE)
    {
        return false;
    }

    if(LoadedItems == MaxLoadedItems)
    {
        AlreadyLoaded = (char **) realloc(AlreadyLoaded, (MaxLoadedItems + LOAD_TREE_ITEMS_INCREMENT) * sizeof(char *));
        MaxLoadedItems = (MaxLoadedItems + LOAD_TREE_ITEMS_INCREMENT);
    }

    AlreadyLoaded[LoadedItems] = (char *) calloc(sizeof(char), strlen(inFolder) + 1);
    strcpy(AlreadyLoaded[LoadedItems], inFolder);
    LoadedItems++;

    do{
        if( strcmp(FindData.cFileName, ".") && strcmp(FindData.cFileName, "..") )
        {
            if(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            {
                HTREEITEM RootLeaf = AddTreeViewItem(SubLeaf, FindData.cFileName, 8, 9);

                if(IndexTwoDeep)
                {
                    if(inFolder[strlen(inFolder) - 1] != '\\')
                        sprintf(DirTemp, "%s\\%s", inFolder, FindData.cFileName);
                    else sprintf(DirTemp, "%s%s", inFolder, FindData.cFileName);

                    IndexDirectoryForSubItem(RootLeaf, DirTemp, false);
                }
            }
        }
    } while(FindNextFile(FileHandle, &FindData));

    FindClose(FileHandle);

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::PopBrowseTree(void)
{
    HTREEITEM DesktopLeaf, MyComputerLeaf, SubLeaf;

    int DriveLoop = 65;  //Drive A
    char PathTemp[MAX_PATH + 1];
    char DriveText[5];
    int DriveType = 0;
    int Image = 0;

    DesktopLeaf = AddTreeViewItem(TVI_ROOT, "Desktop", 6, 6);
    MyComputerLeaf = AddTreeViewItem(DesktopLeaf, "MyComputer", 10, 10);

    while(DriveLoop < 90) //Drive Z
    {
        sprintf(DriveText, "%c:", DriveLoop);
        if((DriveType = GetDriveType(DriveText)) != 1)
        {
            if(DriveType == 0) Image = 0; //Unknown Type
            if(DriveType == 2) Image = 1; //Removable Disk
            if(DriveType == 3) Image = 2; //Fixed Disk
            if(DriveType == 4) Image = 3; //Remote Network Drive
            if(DriveType == 5) Image = 4; //Cd-Rom Drive
            if(DriveType == 6) Image = 5; //High Speed RAM Drive

            SubLeaf = AddTreeViewItem(MyComputerLeaf, DriveText, Image, Image);

            if(DriveType == 3)
            {
                IndexDirectoryForSubItem(SubLeaf, DriveText, false);
            }
        }

        DriveLoop++;
    }

    if(GetDesktopFolderPath(PathTemp))
    {
        IndexDirectoryForSubItem(DesktopLeaf, PathTemp, true);
    }

    TreeView_Expand(lhTreeHandle, DesktopLeaf, TVE_EXPAND);
    TreeView_Expand(lhTreeHandle, MyComputerLeaf, TVE_EXPAND);

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

bool FolderTree::CreateTreeImageList(void)
{
    hImageList = ImageList_Create(16, 16, ILC_COLOR24, 10, 1);

    HBITMAP hBitMap = NULL;

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_UNKNOWN));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_REMOVABLE));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_FIXED));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_NETWORK));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_CDROM));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_RAMDRIVE));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_DESKTOP));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_MYDOCS));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_CLOSEDFOLDER));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_OPENFOLDER));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    hBitMap = LoadBitmap(ghAppInstance, MAKEINTRESOURCE(IDB_TREE_MYCOMPUTER));
    ImageList_Add(hImageList, hBitMap, hBitMap);
    DeleteObject(hBitMap);

    TreeView_SetImageList(lhTreeHandle, hImageList, TVSIL_NORMAL);

    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

BOOL FolderTree::FolderTreeHandler(HWND xHandle, UINT xMessage, WPARAM wParam, LPARAM lParam)
{
    if(xMessage == WM_NOTIFY)
    {
        NMHDR *lpNMH = (LPNMHDR) lParam;

        if(lpNMH->code == TVN_ITEMEXPANDING || lpNMH->code == TVN_SELCHANGED)
        {
            HTREEITEM hItem = NULL;
            HTREEITEM hParent = NULL;

            char FullSelectedPath[MAX_PATH + 1];
            char SubIndexFullPath[MAX_PATH + 1];
            char Itemtext[MAX_PATH + 1];
            char SelectedPath[MAX_PATH + 1];
            char Parent[MAX_PATH + 1];

            int RPos = 0;
            int WPos = MAX_PATH;

            if(lpNMH->code == TVN_ITEMEXPANDING) // If the use is expanding an item
            {
                LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
                hItem = pnmtv->itemNew.hItem;
                TreeView_SelectItem(lhTreeHandle, hItem);
            }
            else { // The user has selected a new tree item
                hItem = TreeView_GetSelection(lhTreeHandle);
            }

            GetTreeItemText(hItem, Itemtext);

            if(strcmpi(Itemtext, "MyComputer") == 0)
            {
                EnableWindow(lhButtonHandle, FALSE);
                return TRUE;
            }

            hParent = hItem;

            // It the desktop itsself selected?
            if(strcmpi(Itemtext, "Desktop") == 0)
            {
                if(GetDesktopFolderPath(FullSelectedPath))
                {
                    if(FullSelectedPath[strlen(FullSelectedPath) - 1] != '\\')
                    {
                        strcat(FullSelectedPath, "\\");
                    }
                    Set_Text(lhEditBoxHandle, FullSelectedPath);
                    EnableWindow(lhButtonHandle, TRUE);
                }
                return TRUE;
            }

            bool AppendDesktop = false;

            // Find out it the item that is selected is a child of the desktop.
            // If it is set AppendDesktop to true.
            while((hParent = TreeView_GetParent(lhTreeHandle, hParent)))
            {
                GetTreeItemText(hParent, Parent);

                if(strcmpi(Parent, "MyComputer") == 0)
                {
                    break;
                }

                if(strcmpi(Parent, "desktop") == 0)
                {
                    AppendDesktop = true;
                    break;
                }
            }

            // Append the name of the selected item to "SelectedPath" in reverse
            RPos = strlen(Itemtext) - 1;
            while(RPos != -1)
            {
                if(Itemtext[RPos] == '\0') break;
                SelectedPath[WPos] = Itemtext[RPos];
                WPos--;
                RPos--;
            }

            //ErrorMessage(NULL, SelectedPath);

            hParent = hItem;

            // Loop through parents of the selected item.
            // Appending there names to SelectedPath in reverse.
            while( (hParent = TreeView_GetParent(lhTreeHandle, hParent)))
            {
                GetTreeItemText(hParent, Itemtext);

                if(strcmpi(Itemtext, "Desktop") == 0 || strcmpi(Itemtext, "MyComputer") == 0)
                {
                    break;
                }

                SelectedPath[WPos--] = '\\';

                RPos = strlen(Itemtext) -1;
                while(RPos != -1)
                {
                    if(Itemtext[RPos] == '\0') break;
                    SelectedPath[WPos] = Itemtext[RPos];
                    WPos--;
                    RPos--;
                }
            }


            // Mirror "SelectedPath" to FullSelectedPath (Reverse)
            // Data from the end of "SelectedPath" to the begining of "FullSelectedPath" and backwards.
            RPos = WPos + 1;
            WPos = 0;
            while(RPos != MAX_PATH+1)
            {
                if(SelectedPath[RPos] == '\0') break;

                FullSelectedPath[WPos] = SelectedPath[RPos];
                WPos++;
                RPos++;
            }

            //MessageBox(GetActiveWindow(), FullSelectedPath, "FullSelectedPath", 0);

            FullSelectedPath[WPos] = '\0';

            // Is the item that is selected a child of the desktop?
            // If so append its path to the end of the desktop path.
            if(AppendDesktop)
            {
                if(GetDesktopFolderPath(SelectedPath))
                {
                    if(SelectedPath[strlen(SelectedPath) - 1] != '\\')
                    {
                        strcat(SelectedPath, "\\");
                    }

                    strcat(SelectedPath, FullSelectedPath); // Append "SelectedPath" to the desktop path
                    strcpy(SubIndexFullPath, SelectedPath); // Save "SubIndexFullPath" for sub indexing

                    strcat(SelectedPath, "\\");
                    Set_Text(lhEditBoxHandle, SelectedPath);

                    EnableWindow(lhButtonHandle, TRUE);
                }
            }
            else{
                strcpy(SubIndexFullPath, FullSelectedPath); // Save "SubIndexFullPath" for sub indexing

                strcat(FullSelectedPath, "\\");
                Set_Text(lhEditBoxHandle, FullSelectedPath);
            }

            IndexDirectoryForSubItem(hItem, SubIndexFullPath, false);

            //---------------------------------------------------------------------------
            // Sub Indexing (Begin)
            // This code it designed to load the directorys into the tree "one level lower"
            // than the user currently has selected. So when (if) they do expand the path
            // its contents are already loaded.

            HTREEITEM hSibling = NULL;

            strcpy(SelectedPath, SubIndexFullPath);

            if((hSibling = TreeView_GetChild(lhTreeHandle, hItem)) != NULL)
            {
                GetTreeItemText(hSibling, Itemtext);

                strcat(SubIndexFullPath, "\\");
                strcat(SubIndexFullPath, Itemtext);

                IndexDirectoryForSubItem(hSibling, SubIndexFullPath, false);

                while((hSibling = TreeView_GetNextSibling(lhTreeHandle, hSibling)) != NULL)
                {
                    GetTreeItemText(hSibling, Itemtext);

                    strcpy(SubIndexFullPath, SelectedPath);
                    strcat(SubIndexFullPath, "\\");
                    strcat(SubIndexFullPath, Itemtext);

                    IndexDirectoryForSubItem(hSibling, SubIndexFullPath, false);
                }
            }

            // Sub Indexing (End)
            //---------------------------------------------------------------------------

            EnableWindow(lhButtonHandle, TRUE);
            return TRUE;
        }
        return FALSE;
    }
    return FALSE;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif

